package cn.scau.server.service.impl;

import cn.scau.server.dto.ApplicationRecordsDTO;
import cn.scau.server.dto.SearchRecordsDTO;
import cn.scau.server.mapper.ApplicationItemRecordsMapper;
import cn.scau.server.pojo.*;
import cn.scau.server.mapper.ApplicationRecordsMapper;
import cn.scau.server.service.*;
import cn.scau.server.vo.RecordItemsVO;
import cn.scau.server.vo.ResultVO;
import cn.scau.server.vo.SingleRecordVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 代码不跑我先跑
 * @since 2025-03-30
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ApplicationRecordsServiceImpl extends ServiceImpl<ApplicationRecordsMapper, ApplicationRecords> implements ApplicationRecordsService {

    @Autowired
    private ProcessInfoService processInfoService;
    @Autowired
    private ProcessNodeService processNodeService;
    @Autowired
    private ApplicationItemRecordsService applicationItemRecordsService;
    @Autowired
    private ApplicationItemsFixedService applicationItemsFixedService;
    @Autowired
    private EmpService empService;
    @Autowired
    private EmpPosService empPosService;
    @Autowired
    private DeptService deptService;
    @Autowired
    private NotificationService notificationService;
    @Autowired
    private AttendanceService attendanceService;
    @Autowired
    private ApplicationItemsService applicationItemsService;

    @Autowired
    private ApplicationRecordsMapper applicationRecordsMapper;
    @Autowired
    private ApplicationItemRecordsMapper applicationItemRecordsMapper;

    @Override
    public ResultVO addRecord(ApplicationRecordsDTO applicationRecordsDTO) {
        //先往数据库添加record记录
        //1.检查工号、申请类型是否存在
        String empId = applicationRecordsDTO.getEmpId();
        Integer flowId = applicationRecordsDTO.getFlowId();
        //1.1 工号
        Emp emp = getEmp(empId);
        if(emp == null) {
            return ResultVO.fail("此工号不存在！");
        }
        //1.2 申请类型
        QueryWrapper<ProcessInfo> processInfoQueryWrapper = new QueryWrapper<>();
        processInfoQueryWrapper.eq("id", flowId);
        processInfoQueryWrapper.eq("is_using",true);
        ProcessInfo processInfo = processInfoService.getOne(processInfoQueryWrapper);
        if(processInfo == null) {
            return ResultVO.fail("此流程类型不存在");
        }

        //2.添加记录
        //2.1先获得这种流程的各个节点，判断到第几步才需要领导审批，然后获得status
        Integer status = processNodeService.getInitStatus(flowId);
        //先判断是不是领导，是领导就给上一级领导请假，不然就是找自己的领导请假
        QueryWrapper<EmpPos> empPosQueryWrapper = new QueryWrapper<>();
        Integer deptId1 = applicationRecordsDTO.getDeptId();
        empPosQueryWrapper.eq("emp_id", empId);
        empPosQueryWrapper.eq("dept_id",deptId1);
        EmpPos one = empPosService.getOne(empPosQueryWrapper);
        Integer deptId = 0;
        if(one.getIsLeader()==1){
            //是领导
            deptId = deptService.findParent(applicationRecordsDTO.getDeptId());
        }else{
            //不是领导
            deptId = deptId1;
        }
        Integer remainPriority = processNodeService.getRemainPriority(flowId,status);
        //2.2创建记录
        ApplicationRecords applicationRecords = new ApplicationRecords();
        applicationRecords.setEmpId(empId);
        applicationRecords.setFlowId(flowId);
        applicationRecords.setStatus(status);
        applicationRecords.setDeptId(deptId);
        applicationRecords.setRemainPriority(remainPriority);
        //2.3存入数据库中
        boolean save = save(applicationRecords);
        if(!save) {
            return ResultVO.fail("存储失败！");
        }

        //3.添加记录申请项
        //3.1获得刚刚创建的记录id
        Integer recordId = applicationRecords.getId();
        //3.2处理记录流动申请项数组
        List<ApplicationItemRecords> items = applicationRecordsDTO.getItems();
        items.forEach(item->{
            item.setRecId(recordId);
            boolean saveItem = applicationItemRecordsService.save(item);
            if(!saveItem) {
                log.error("存储记录项失败！");
            }
        });
        //3.3处理记录中固定申请项
        ApplicationItemsFixed applicationItemsFixed = applicationRecordsDTO.getItemsFixed();
        applicationItemsFixed.setRecordId(recordId);
        boolean itemsFixedSave = applicationItemsFixedService.save(applicationItemsFixed);
        if(!itemsFixedSave) {
            return ResultVO.fail("存储失败！");
        }

        //4.返回
        return ResultVO.success("存储成功！",true);
    }

    @Override
    public ResultVO getPersonalRecords(SearchRecordsDTO searchRecordsDTO) {
        //1.先查一下工号存不存在
        String empId = searchRecordsDTO.getEmpId();
        if(empId == null) {
            return ResultVO.fail("请先传工号！");
        }
        Emp emp = getEmp(empId);
        if(emp == null) {
            return ResultVO.fail("此工号不存在");
        }

        //2.查询对应记录信息
        //2.1 先查询记录的相关信息
        //员工工号、状态号、申请类型号、状态名称、申请类型名称、记录号
        List<SingleRecordVO> records = applicationRecordsMapper.getSingleRecordInfo(searchRecordsDTO);
        //2.2 查询每条记录的具体项，并封装
        records.forEach(record->{
            //2.2.1 查询每条记录的流动项并封装
            List<RecordItemsVO> items = applicationItemRecordsMapper.getItem(record.getRecordId());
            if(items.isEmpty()) {
               log.error("查询单条某记录项失败！");
            }else{
                record.setItems(items);
            }
            //2.2.2 查询每条记录的固定项并封装
            QueryWrapper<ApplicationItemsFixed> applicationItemsFixedQueryWrapper = new QueryWrapper<>();
            applicationItemsFixedQueryWrapper.eq("record_id", record.getRecordId());
            ApplicationItemsFixed one = applicationItemsFixedService.getOne(applicationItemsFixedQueryWrapper);
            if(one==null){
                log.error("查询单条记录固定项失败！");
            }
            record.setApplicationItemsFixed(one);
            //2.2.3 查询记录的状态，并作设置
            if(processNodeService.isLastStatus(record.getStatusId(),record.getFlowId())){
                record.setStatus("审核完成");
            }
        });

        //3.返回
        return ResultVO.success("查询成功！",records);
    }

    @Override
    public ResultVO getPersonalSingleRecords(Integer recordId, String empId) {
        SingleRecordVO singleRecordVO = applicationRecordsMapper.getPersonalSingleRecord(recordId,empId);
        List<RecordItemsVO> items = applicationItemRecordsMapper.getItem(recordId);
        singleRecordVO.setItems(items);
        QueryWrapper<ApplicationItemsFixed> applicationItemsFixedQueryWrapper = new QueryWrapper<>();
        applicationItemsFixedQueryWrapper.eq("record_id", recordId);
        ApplicationItemsFixed one = applicationItemsFixedService.getOne(applicationItemsFixedQueryWrapper);
        if(one==null){
            return ResultVO.fail("获取单条固定项信息失败！");
        }
        singleRecordVO.setApplicationItemsFixed(one);
        //2.2.3 查询记录的状态，并作设置
        if(processNodeService.isLastStatus(singleRecordVO.getStatusId(),singleRecordVO.getFlowId())){
            singleRecordVO.setStatus("审核完成");
        }
        return ResultVO.success("成功获取",singleRecordVO);
    }

    @Override
    public ResultVO getLeaderApprovalList(SearchRecordsDTO searchRecordsDTO) {
        //1.先判断是不是部门领导发来的请求
        Integer leader = searchRecordsDTO.getIsLeader();
        if(leader==0) {
           return ResultVO.fail("不是部门领导，不可以请求");
        }
        //2.查询记录信息
        //2.1 先查询记录相关信息，并且在mapper筛选出需要这个部门领导去审批的
        List<SingleRecordVO> records = applicationRecordsMapper.getApprovalList(searchRecordsDTO);
        records.forEach(record->{
            //2.2.1 查询每条记录的具体项，并封装
            List<RecordItemsVO> items = applicationItemRecordsMapper.getItem(record.getRecordId());
            if(items.isEmpty()) {
                log.error("查询单条记录失败！");
            }else{
                record.setItems(items);
            }

            //2.2.2 查询每条记录的固定项并封装
            QueryWrapper<ApplicationItemsFixed> applicationItemsFixedQueryWrapper = new QueryWrapper<>();
            applicationItemsFixedQueryWrapper.eq("record_id", record.getRecordId());
            ApplicationItemsFixed one = applicationItemsFixedService.getOne(applicationItemsFixedQueryWrapper);
            if(one==null){
                log.error("查询单条记录固定项失败！");
            }
            record.setApplicationItemsFixed(one);

            //2.2.3 查询记录的状态，并作设置
            if(processNodeService.isLastStatus(record.getStatusId(),record.getFlowId())){
                record.setStatus("审核完成");
            }
        });

        //3.返回
        return ResultVO.success("查询成功！",records);
    }



    @Override
    public ResultVO revokeApplication(Integer recordId) {
        //直接将状态设为-1
        UpdateWrapper<ApplicationRecords> applicationRecordsUpdateWrapper = new UpdateWrapper<>();
        applicationRecordsUpdateWrapper.eq("id", recordId).set("status", -1).set("dept_id",-1);
        boolean update = update(applicationRecordsUpdateWrapper);
        if(!update) {
            return ResultVO.fail("更新失败！");
        }
        return ResultVO.success("更新成功！");
    }

    @Override
    public ResultVO approval(Integer recordId, Integer deptId, String empId, Boolean pass) throws ParseException {
        //1.这个记录存不存在
        QueryWrapper<ApplicationRecords> applicationRecordsQueryWrapper = new QueryWrapper<>();
        applicationRecordsQueryWrapper.eq("id", recordId);
        ApplicationRecords record = getOne(applicationRecordsQueryWrapper);
        if(record == null) {
            return ResultVO.fail("此记录不存在！");
        }
        //2.这个领导存不存在
        QueryWrapper<EmpPos> empPosQueryWrapper = new QueryWrapper<>();
        empPosQueryWrapper.eq("emp_id", empId);
        empPosQueryWrapper.eq("dept_id", deptId);
        EmpPos leader = empPosService.getOne(empPosQueryWrapper);
        if(leader == null) {
            return ResultVO.fail("此领导不存在!");
        }
        if(leader.getIsLeader()==0){
            return ResultVO.fail("该员工不是领导！");
        }

        //3.判断一下是通过还是驳回
        if(!pass){
            //3.1 驳回，将状态设为-2
            return rejectApplication(record,empId);
        }
        //3.2.通过
        return passApplication(record,deptId,empId);
    }

    private ResultVO passApplication(ApplicationRecords record, Integer deptId,String empId) throws ParseException {
        //1.更新status
        Integer nextStatus = processNodeService.getNextStatus(record.getStatus(),record.getFlowId());
        //2.判断是不是虚拟尾节点/逻辑尾节点
        if(processNodeService.isLastStatus(nextStatus,record.getFlowId())){
            //2.1 是虚拟尾节点就说明审核都结束了
            UpdateWrapper<ApplicationRecords> applicationRecordsUpdateWrapper = new UpdateWrapper<>();
            applicationRecordsUpdateWrapper.eq("id", record.getId()).set("status", nextStatus).set("dept_id", -1).set("remain_priority",0);
            boolean update = update(applicationRecordsUpdateWrapper);
            if(!update) {
                return ResultVO.fail("审批失败！");
            }
            //2.2 发通知
            boolean send = sendNotification(record, empId, nextStatus);
            if(!send) {
                return ResultVO.fail("发送失败");
            }
            //2.3 修改签到状态
            String processName = processInfoService.getProcessNameById(record.getFlowId());
            List<ApplicationItemRecords> original = getRecordItems(record.getId());
            List<ApplicationItemRecords> items = new ArrayList<>(original);
            if(processName.contains("出差")){
                LocalDate startLocalDate = LocalDate.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("出发时间")){
                        String startTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(startTime);
                        // 2. 提取日期部分（LocalDate）
                        startLocalDate = dateTime.toLocalDate();
                        break;
                    }
                }
                LocalDate endLocalDate = LocalDate.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("返回时间")){
                        String endTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(endTime);
                        // 2. 提取日期部分（LocalDate）
                        endLocalDate = dateTime.toLocalDate();
                        break;
                    }
                }
                while (!startLocalDate.isAfter(endLocalDate)) {
                    attendanceService.recordTripOrLeave(record.getEmpId(), startLocalDate,2);
                    startLocalDate = startLocalDate.plusDays(1); // 增加一天
                }
            }else if(processName.contains("请假")){
                LocalDate startLocalDate = LocalDate.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("开始时间")){
                        String startTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(startTime);
                        // 2. 提取日期部分（LocalDate）
                        startLocalDate = dateTime.toLocalDate();
                        break;
                    }
                }
                LocalDate endLocalDate = LocalDate.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("结束时间")){
                        String endTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(endTime);
                        // 2. 提取日期部分（LocalDate）
                        endLocalDate = dateTime.toLocalDate();
                        break;
                    }
                }
                while (!startLocalDate.isAfter(endLocalDate)) {
                    System.out.println("请假: "+record.getEmpId()+" "+startLocalDate);
                    attendanceService.recordTripOrLeave(record.getEmpId(), startLocalDate,1);
                    startLocalDate = startLocalDate.plusDays(1); // 增加一天
                }
            }else if(processName.contains("补签到")){
                LocalDate startLocalDate = LocalDate.now();
                LocalDateTime startDateTime = LocalDateTime.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("补签时间")){
                        String startTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(startTime);
                        // 2. 提取日期部分（LocalDate）
                        startLocalDate = dateTime.toLocalDate();

                        // 1. 解析为 OffsetDateTime（处理时区）
                        OffsetDateTime offsetDateTime = OffsetDateTime.parse(startTime);

                        // 2. 提取日期部分（LocalDate）
                        LocalDate date = offsetDateTime.toLocalDate();

                        // 3. 创建新的 LocalDateTime：日期不变，时间设为 09:00:00
                        startDateTime = date.atTime(9, 0, 0); // 09:00:00
                        break;
                    }
                }
//                System.out.println("补签到: "+record.getEmpId()+" "+startLocalDate+" "+startDateTime);
                attendanceService.repair(record.getEmpId(), startLocalDate,1,startDateTime);
            }else if(processName.contains("补签退")){
                LocalDate startLocalDate = LocalDate.now();
                LocalDateTime startDateTime = LocalDateTime.now();
                for (ApplicationItemRecords item : items) {
                    QueryWrapper<ApplicationItems> applicationItemsQueryWrapper = new QueryWrapper<>();
                    applicationItemsQueryWrapper.eq("id", item.getItemId());
                    ApplicationItems one = applicationItemsService.getOne(applicationItemsQueryWrapper);
                    if(one.getItemName().contains("补签时间")){
                        String startTime = item.getItemValue();
                        // 1. 解析带时区的字符串
                        OffsetDateTime dateTime = OffsetDateTime.parse(startTime);
                        // 2. 提取日期部分（LocalDate）
                        startLocalDate = dateTime.toLocalDate();

                        OffsetDateTime offsetDateTime = OffsetDateTime.parse(startTime);
                        LocalDate date = offsetDateTime.toLocalDate();
                        startDateTime = date.atTime(17, 0, 0); // 09:00:00
                        break;
                    }
                }
                attendanceService.repair(record.getEmpId(), startLocalDate,2,startDateTime);
            }
            return ResultVO.success("审批完成！");
        }
        //3.不是虚拟节点，继续推进进度
        //3.1 找到下一个要传过去部门
        Integer remainPriority = processNodeService.getRemainPriority(record.getFlowId(),nextStatus);
        Integer layers = remainPriority;
        QueryWrapper<EmpPos> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("emp_id", record.getEmpId());
        EmpPos one = empPosService.getOne(queryWrapper);
        Integer parentDeptId = one.getDeptId();
        Integer isLeader = one.getIsLeader();
        if(isLeader==0){
            layers--;
        }
        while(layers != 0){
            parentDeptId = deptService.findParent(parentDeptId);
            layers--;
        }
        UpdateWrapper<ApplicationRecords> applicationRecordsUpdateWrapper = new UpdateWrapper<>();
        applicationRecordsUpdateWrapper.eq("id", record.getId()).set("status",nextStatus).set("dept_id",parentDeptId).set("remain_priority",remainPriority);
        boolean update = update(applicationRecordsUpdateWrapper);
        if(!update) {
            return ResultVO.fail("审批失败！");
        }
        boolean send = sendNotification(record, empId, nextStatus);
        if(!send) {
            return ResultVO.fail("发送失败");
        }
        return ResultVO.success("审批继续");
    }

    private List<ApplicationItemRecords> getRecordItems(Integer recordId) {
        QueryWrapper<ApplicationItemRecords> applicationItemRecordsQueryWrapper = new QueryWrapper<>();
        applicationItemRecordsQueryWrapper.eq("rec_id", recordId);
        List<ApplicationItemRecords> list = applicationItemRecordsService.list(applicationItemRecordsQueryWrapper);
        if(list.isEmpty()) {
            return null;
        }
        return list;
    }

    private boolean sendNotification(ApplicationRecords record, String empId, Integer status) throws ParseException {
        Notification notification = new Notification();
        notification.setEmpId(record.getEmpId());
        notification.setLeaderId(empId);
        String content = processNodeService.isLastStatus(status,record.getFlowId())?
                "你的 "+processInfoService.getProcessNameById(record.getFlowId())+"申请已审批完成":
                "你的"+processInfoService.getProcessNameById(record.getFlowId())+
                        "申请已进行到 "+processNodeService.
                        getStatusName(record.getFlowId(), status)+" 环节";
        notification.setContent(content);
        Date send_time = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置日期格式为年-月-日
        String formattedSendTime = dateFormat.format(send_time); // 格式化日
        send_time = dateFormat.parse(formattedSendTime);
        notification.setSendTime(send_time);
        notification.setIsRead(0);
        return notificationService.save(notification);
    }


    private ResultVO rejectApplication(ApplicationRecords record, String empId) throws ParseException {
        //直接将状态设为-2
        UpdateWrapper<ApplicationRecords> applicationRecordsUpdateWrapper = new UpdateWrapper<>();
        applicationRecordsUpdateWrapper.eq("id", record.getId()).set("status", -2);
        applicationRecordsUpdateWrapper.set("dept_id", -1);
        applicationRecordsUpdateWrapper.set("remain_priority", 0);
        boolean update = update(applicationRecordsUpdateWrapper);
        if(!update) {
            return ResultVO.fail("更新失败！");
        }
        sendNotification(record,empId, -2);
        return ResultVO.success("更新成功！");
    }

    private Emp getEmp(String empId) {
        QueryWrapper<Emp> empQueryWrapper = new QueryWrapper<>();
        empQueryWrapper.eq("is_deleted", false);
        empQueryWrapper.eq("emp_id", empId);
        return empService.getOne(empQueryWrapper);
    }
}
